package org.sam.swing.table.model;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import javax.swing.RowFilter;
import javax.swing.RowFilter.ComparisonType;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.jdesktop.swingx.sort.RowFilters;
import org.jdesktop.swingx.sort.RowFilters.GeneralFilter;
import org.jdesktop.swingx.util.Contract;
import org.sam.swing.table.JSTableColumn;

/**
 * 
 * @author sam
 *
 */
public interface FilterOperation {

	/**
	 * 包含
	 */
	public static final String CONTAINS = "包含";

	/**
	 * 包括
	 */
	public static final String IN = "in";

	/**
	 * 等于
	 */
	public static final String EQUAL = "=";

	/**
	 * 不等于
	 */
	public static final String NOTEQUAL = "<>";

	/**
	 * 大于
	 */
	public static final String MORETHAN = ">";

	/**
	 * 小于
	 */
	public static final String LESSTHAN = "<";

	/**
	 * 空操作类型
	 */
	public static final String EMPTY = "";

	/**
	 * 逻辑与操作
	 */
	public static final String AND = "and";

	/**
	 * 逻辑与操作
	 */
	public static final String OR = "or";

	/**
	 * 一个左括号
	 */
	public static final String LEFT_ONE_BRACKETS = "(";

	/**
	 * 两个左括号
	 */
	public static final String LEFT_TWO_BRACKETS = "((";

	/**
	 * 三个左括号
	 */
	public static final String LEFT_THREE_BRACKETS = "(((";

	/**
	 * 一个右括号
	 */
	public static final String RIGHT_ONE_BRACKETS = ")";

	/**
	 * 两个右括号
	 */
	public static final String RIGHT_TWO_BRACKETS = "))";

	/**
	 * 三个右括号
	 */
	public static final String RIGHT_THREE_BRACKETS = ")))";

	/**
	 * 格式化日期时间格式的掩码
	 */
	public static final SimpleDateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd");

	/**
	 * 获取当前操作的过滤对象集合
	 * 
	 * @return
	 */
	public List<FilterObject> getFilterObjects();

	/**
	 * 设置过滤对象集合
	 * 
	 * @param fitlers
	 */
	public void setFilterObjects(List<FilterObject> fitlers);

	/**
	 * 返回绑定名称 + 显示名称的列数据结构
	 * 
	 * @param colModel
	 * @return
	 */
	public static Map<String, String> getColumnNamesMapWithDisplay(TableColumnModel colModel) {
		Map<String, String> colNames = new LinkedHashMap<>();
		if (colModel == null)
			return colNames;

		Enumeration<TableColumn> columns = colModel.getColumns();
		while (columns.hasMoreElements()) {
			TableColumn column = columns.nextElement();
			if (column == null)
				continue;

			if (column instanceof JSTableColumn) {
				JSTableColumn col = (JSTableColumn) column;
				if (col.getIdentifier() == null || col.getIdentifier().toString().length() <= 0 || !col.isVisible())
					continue;

				colNames.put(col.getIdentifier().toString(), col.getTitle());
			}
		}

		return colNames;
	}

	/**
	 * 使用设置条件生成过滤对象(多条件复杂实现)
	 * 
	 * @param colModel
	 * @param filterObjects
	 * @return
	 */
	public static RowFilter<? super TableModel, ? super Integer> getRowFilterWithMulityCondition(
			TableColumnModel colModel, List<FilterObject> filterObjects) {

		if (filterObjects == null || filterObjects.isEmpty())
			return null;

		Stack<FilterObject> stack = new Stack<>();
		List<RowFilter<Object, Object>> filters = new ArrayList<>();
		// 最后一次的操作，直接影响到最后的对象
		String lastFitlerObject = EMPTY;
		RowFilter<Object, Object> result = null;

		for (FilterObject filterObject : filterObjects) {
			if (EMPTY.equals(filterObject.getLeftBrackets())) {
				// 如果是无拼接操作
				stack.push(filterObject);

			} else if (LEFT_ONE_BRACKETS.equals(filterObject.getLeftBrackets())) {

			} else if (LEFT_TWO_BRACKETS.equals(filterObject.getLeftBrackets())) {

			} else if (LEFT_THREE_BRACKETS.equals(filterObject.getLeftBrackets())) {

			}
			// 设置最后一个操作
			lastFitlerObject = filterObject.getLeftBrackets();
		}

		switch (lastFitlerObject) {
		case AND:
		case EMPTY:
			result = RowFilter.andFilter(filters);
			break;
		case OR:
			result = RowFilter.orFilter(filters);
			break;
		}
		return result;
	}

	/**
	 * 单层级别简单实现（值判断or和and）
	 * 
	 * @param tableModel
	 * @param colModel
	 * @param filterObjects
	 * @return
	 */
	public static RowFilter<? super TableModel, ? super Integer> getRowFilterSimple(TableModel tableModel,
			TableColumnModel colModel, List<FilterObject> filterObjects) {

		if (filterObjects == null || filterObjects.isEmpty())
			return null;

		Stack<FilterObject> stack = new Stack<>();
		List<RowFilter<Object, Object>> filters = new ArrayList<>();
		// 最后一次的操作，直接影响到最后的对象
		String lastFitlerObject = EMPTY;
		RowFilter<Object, Object> result = null;

		for (FilterObject filterObject : filterObjects) {
			if (!EMPTY.equals(lastFitlerObject) && !lastFitlerObject.equals(filterObject.getConnectCondition())) {
				// 出栈，直到条件不一样或者只剩下一个条件，必须出栈
				filters.add(popFilterObjectUntil(stack, tableModel, colModel, lastFitlerObject));
			} else {
				// 入栈条件，1 最后的操作相等 或者 2 第一次操作
				stack.push(filterObject);
			}

			// 最后一次的操作是and还是or
			lastFitlerObject = filterObject.getConnectCondition();
		}

		if (!stack.isEmpty()) {
			filters.add(popFilterObjectUntil(stack, tableModel, colModel, lastFitlerObject));
		}

		switch (lastFitlerObject) {
		case AND:
		case EMPTY:
			result = RowFilter.andFilter(filters);
			break;
		case OR:
			result = RowFilter.orFilter(filters);
			break;
		default:
			return null;
		}
		return result;

	}

	/**
	 * 出栈直到条件不一致
	 * 
	 * @param stack      已经入栈的数据
	 * @param tableModel
	 * @param colModel
	 * @param condition  当前的出栈条件
	 * @return
	 */
	public static RowFilter<Object, Object> popFilterObjectUntil(Stack<FilterObject> stack, TableModel tableModel,
			TableColumnModel colModel, String condition) {

		if (stack == null || stack.isEmpty())
			return null;

		List<RowFilter<Object, Object>> filters = new LinkedList<>();
		RowFilter<Object, Object> result = null;

		while (!stack.empty()) {
			FilterObject filter = stack.peek();
			if (EMPTY.equals(filter.getConnectCondition()) || condition.equals(filter.getConnectCondition())) {
				stack.pop();
				filters.add(convertRowFilter(tableModel, colModel, filter));
			} else {
				break;
			}
		}

		switch (condition) {
		case AND:
		case EMPTY:
			result = RowFilter.andFilter(filters);
			break;
		case OR:
			result = RowFilter.orFilter(filters);
			break;
		}
		return result;
	}

	/**
	 * 将操作对象转换为RowFilter对象
	 * 
	 * @param tableModel 表格操作对象
	 * @param colModel   列操作对象
	 * @param filter     过滤对象
	 * @return
	 */
	public static RowFilter<Object, Object> convertRowFilter(TableModel tableModel, TableColumnModel colModel,
			FilterObject filter) {

		if (filter == null || colModel == null)
			return null;

		if (StringUtils.isEmpty(filter.getFiled()))
			return null;

		int colIndex = colModel.getColumnIndex(filter.getFiled());
		Class<?> cls = tableModel.getColumnClass(colIndex);
		return convertRowFilter(cls, filter.getCondition(), colIndex, filter.getPatternValue());
	}

	/**
	 * 使用最原始的条件生成过滤条件对象
	 * 
	 * @param cls       字段数据类型
	 * @param condition 拼接条件
	 * @param colIndex  字段序号
	 * @param value     值
	 * @return
	 */
	public static RowFilter<Object, Object> convertRowFilter(Class<?> cls, String condition, int colIndex,
			String value) {

		if (StringUtils.isEmpty(condition))
			return null;

		RowFilter<Object, Object> result = null;

		switch (condition) {
		case CONTAINS: {
			result = RowFilters.regexFilter(value, colIndex);
			break;
		}
		case IN: {
			String[] split = value.split(",");
			List<RowFilter<Object, Object>> results = new ArrayList<>();
			for (String s : split) {
				if (String[].class.equals(cls)) {
					results.add(new StringArrayFilter(s, colIndex));
				}
			}
			result = RowFilter.andFilter(results);
			break;
		}
		case EQUAL: {
			if (cls == null) {
				result = RowFilters.regexFilter(value, colIndex);
			} else if (Date.class.equals(cls)) {
				result = RowFilter.dateFilter(ComparisonType.EQUAL, covertDate(value), colIndex);
			} else if (Short.class.equals(cls) || Integer.class.equals(cls) || Long.class.equals(cls)
					|| Float.class.equals(cls) || Double.class.equals(cls)) {
				result = RowFilter.numberFilter(RowFilter.ComparisonType.EQUAL, Double.valueOf(value), colIndex);
			} else {
				result = RowFilters.regexFilter(value, colIndex);
			}
			break;
		}
		case NOTEQUAL: {
			if (cls == null) {
				result = RowFilters.regexFilter(value, colIndex);
			} else if (Date.class.equals(cls)) {
				result = RowFilter.dateFilter(ComparisonType.NOT_EQUAL, covertDate(value), colIndex);
			} else if (Short.class.equals(cls) || Integer.class.equals(cls) || Long.class.equals(cls)
					|| Float.class.equals(cls) || Double.class.equals(cls)) {
				result = RowFilter.numberFilter(RowFilter.ComparisonType.NOT_EQUAL, Double.valueOf(value), colIndex);
			} else {
				result = RowFilters.regexFilter(value, colIndex);
			}
			break;
		}
		case MORETHAN: {
			if (cls == null) {
				result = RowFilters.regexFilter(value, colIndex);
			} else if (Date.class.equals(cls)) {
				result = RowFilter.dateFilter(ComparisonType.AFTER, covertDate(value), colIndex);
			} else if (Short.class.equals(cls) || Integer.class.equals(cls) || Long.class.equals(cls)
					|| Float.class.equals(cls) || Double.class.equals(cls)) {
				result = RowFilter.numberFilter(RowFilter.ComparisonType.AFTER, Double.valueOf(value), colIndex);
			} else {
				result = RowFilters.regexFilter(value, colIndex);
			}
			break;
		}
		case LESSTHAN: {
			if (cls == null) {
				result = RowFilters.regexFilter(value, colIndex);
			} else if (Date.class.equals(cls)) {
				result = RowFilter.dateFilter(ComparisonType.BEFORE, covertDate(value), colIndex);
			} else if (Short.class.equals(cls) || Integer.class.equals(cls) || Long.class.equals(cls)
					|| Float.class.equals(cls) || Double.class.equals(cls)) {
				result = RowFilter.numberFilter(RowFilter.ComparisonType.BEFORE, Double.valueOf(value), colIndex);
			} else {
				result = RowFilters.regexFilter(value, colIndex);
			}
			break;
		}
		default: {
			result = RowFilters.regexFilter(value, colIndex);
			break;
		}
		}
		return result;
	}

	/**
	 * 转换字符串为date的方法
	 * 
	 * @param value
	 * @return
	 */
	public static Date covertDate(String value) {
		try {
			Date result = dateFormater.parse(value);
			return result;
		} catch (Exception ex) {
			throw new RuntimeException("请输入正确的日期格式,比如:2020-01-01");
		}
	}

	public static class StringArrayFilter extends GeneralFilter {
		
		private String regex;
		
		StringArrayFilter(String regex, int... columns) {
			super(columns);
			if (regex == null) {
				Contract.asNotNull(regex, "Pattern must be non-null");
			}
			this.regex = regex;
		}

		@Override
		protected boolean include(Entry<? extends Object, ? extends Object> value, int index) {
			Object array = value.getValue(index);
			if (array instanceof String[]) {
				return ArrayUtils.contains((String[])array, this.regex);
			}
			return false;
		}

	}
}
